{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 目录"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc": true
   },
   "source": [
    "<h1>Table of Contents<span class=\"tocSkip\"></span></h1>\n",
    "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#目录\" data-toc-modified-id=\"目录-1\"><span class=\"toc-item-num\">1&nbsp;&nbsp;</span>目录</a></span></li><li><span><a href=\"#Chapter2\" data-toc-modified-id=\"Chapter2-2\"><span class=\"toc-item-num\">2&nbsp;&nbsp;</span>Chapter2</a></span><ul class=\"toc-item\"><li><span><a href=\"#用户行为分析\" data-toc-modified-id=\"用户行为分析-2.1\"><span class=\"toc-item-num\">2.1&nbsp;&nbsp;</span>用户行为分析</a></span><ul class=\"toc-item\"><li><span><a href=\"#用户活跃度和物品流行度的分布\" data-toc-modified-id=\"用户活跃度和物品流行度的分布-2.1.1\"><span class=\"toc-item-num\">2.1.1&nbsp;&nbsp;</span>用户活跃度和物品流行度的分布</a></span></li><li><span><a href=\"#用户活跃度和物品流行度的关系\" data-toc-modified-id=\"用户活跃度和物品流行度的关系-2.1.2\"><span class=\"toc-item-num\">2.1.2&nbsp;&nbsp;</span>用户活跃度和物品流行度的关系</a></span></li></ul></li><li><span><a href=\"#基于邻域方法\" data-toc-modified-id=\"基于邻域方法-2.2\"><span class=\"toc-item-num\">2.2&nbsp;&nbsp;</span>基于邻域方法</a></span><ul class=\"toc-item\"><li><span><a href=\"#ＵSERCF\" data-toc-modified-id=\"ＵSERCF-2.2.1\"><span class=\"toc-item-num\">2.2.1&nbsp;&nbsp;</span>ＵSERCF</a></span><ul class=\"toc-item\"><li><span><a href=\"#Load-Data\" data-toc-modified-id=\"Load-Data-2.2.1.1\"><span class=\"toc-item-num\">2.2.1.1&nbsp;&nbsp;</span>Load Data</a></span></li><li><span><a href=\"#Training\" data-toc-modified-id=\"Training-2.2.1.2\"><span class=\"toc-item-num\">2.2.1.2&nbsp;&nbsp;</span>Training</a></span></li><li><span><a href=\"#Evaluation\" data-toc-modified-id=\"Evaluation-2.2.1.3\"><span class=\"toc-item-num\">2.2.1.3&nbsp;&nbsp;</span>Evaluation</a></span></li></ul></li><li><span><a href=\"#USER-IIF\" data-toc-modified-id=\"USER-IIF-2.2.2\"><span class=\"toc-item-num\">2.2.2&nbsp;&nbsp;</span>USER-IIF</a></span><ul class=\"toc-item\"><li><span><a href=\"#Load-Data\" data-toc-modified-id=\"Load-Data-2.2.2.1\"><span class=\"toc-item-num\">2.2.2.1&nbsp;&nbsp;</span>Load Data</a></span></li><li><span><a href=\"#Training\" data-toc-modified-id=\"Training-2.2.2.2\"><span class=\"toc-item-num\">2.2.2.2&nbsp;&nbsp;</span>Training</a></span></li><li><span><a href=\"#Evaluation\" data-toc-modified-id=\"Evaluation-2.2.2.3\"><span class=\"toc-item-num\">2.2.2.3&nbsp;&nbsp;</span>Evaluation</a></span></li></ul></li><li><span><a href=\"#ITEMCF\" data-toc-modified-id=\"ITEMCF-2.2.3\"><span class=\"toc-item-num\">2.2.3&nbsp;&nbsp;</span>ITEMCF</a></span><ul class=\"toc-item\"><li><span><a href=\"#Load-Data\" data-toc-modified-id=\"Load-Data-2.2.3.1\"><span class=\"toc-item-num\">2.2.3.1&nbsp;&nbsp;</span>Load Data</a></span></li><li><span><a href=\"#Training\" data-toc-modified-id=\"Training-2.2.3.2\"><span class=\"toc-item-num\">2.2.3.2&nbsp;&nbsp;</span>Training</a></span></li><li><span><a href=\"#Evaluation\" data-toc-modified-id=\"Evaluation-2.2.3.3\"><span class=\"toc-item-num\">2.2.3.3&nbsp;&nbsp;</span>Evaluation</a></span></li></ul></li><li><span><a href=\"#ITEMCF-IUF\" data-toc-modified-id=\"ITEMCF-IUF-2.2.4\"><span class=\"toc-item-num\">2.2.4&nbsp;&nbsp;</span>ITEMCF-IUF</a></span><ul class=\"toc-item\"><li><span><a href=\"#Load-Data\" data-toc-modified-id=\"Load-Data-2.2.4.1\"><span class=\"toc-item-num\">2.2.4.1&nbsp;&nbsp;</span>Load Data</a></span></li><li><span><a href=\"#Train-Model\" data-toc-modified-id=\"Train-Model-2.2.4.2\"><span class=\"toc-item-num\">2.2.4.2&nbsp;&nbsp;</span>Train Model</a></span></li><li><span><a href=\"#Evaluation\" data-toc-modified-id=\"Evaluation-2.2.4.3\"><span class=\"toc-item-num\">2.2.4.3&nbsp;&nbsp;</span>Evaluation</a></span></li></ul></li><li><span><a href=\"#ITEMCF-NORM\" data-toc-modified-id=\"ITEMCF-NORM-2.2.5\"><span class=\"toc-item-num\">2.2.5&nbsp;&nbsp;</span>ITEMCF-NORM</a></span><ul class=\"toc-item\"><li><span><a href=\"#Load-Data\" data-toc-modified-id=\"Load-Data-2.2.5.1\"><span class=\"toc-item-num\">2.2.5.1&nbsp;&nbsp;</span>Load Data</a></span></li><li><span><a href=\"#Train-Model\" data-toc-modified-id=\"Train-Model-2.2.5.2\"><span class=\"toc-item-num\">2.2.5.2&nbsp;&nbsp;</span>Train Model</a></span></li><li><span><a href=\"#Evaluation\" data-toc-modified-id=\"Evaluation-2.2.5.3\"><span class=\"toc-item-num\">2.2.5.3&nbsp;&nbsp;</span>Evaluation</a></span></li></ul></li></ul></li></ul></li><li><span><a href=\"#Chapter3\" data-toc-modified-id=\"Chapter3-3\"><span class=\"toc-item-num\">3&nbsp;&nbsp;</span>Chapter3</a></span></li><li><span><a href=\"#Chapter4\" data-toc-modified-id=\"Chapter4-4\"><span class=\"toc-item-num\">4&nbsp;&nbsp;</span>Chapter4</a></span><ul class=\"toc-item\"><li><span><a href=\"#标签流行度长尾趋势\" data-toc-modified-id=\"标签流行度长尾趋势-4.1\"><span class=\"toc-item-num\">4.1&nbsp;&nbsp;</span>标签流行度长尾趋势</a></span></li><li><span><a href=\"#基于标签的基本推荐\" data-toc-modified-id=\"基于标签的基本推荐-4.2\"><span class=\"toc-item-num\">4.2&nbsp;&nbsp;</span>基于标签的基本推荐</a></span><ul class=\"toc-item\"><li><span><a href=\"#Load-Data\" data-toc-modified-id=\"Load-Data-4.2.1\"><span class=\"toc-item-num\">4.2.1&nbsp;&nbsp;</span>Load Data</a></span></li><li><span><a href=\"#Training\" data-toc-modified-id=\"Training-4.2.2\"><span class=\"toc-item-num\">4.2.2&nbsp;&nbsp;</span>Training</a></span></li><li><span><a href=\"#Evaluation\" data-toc-modified-id=\"Evaluation-4.2.3\"><span class=\"toc-item-num\">4.2.3&nbsp;&nbsp;</span>Evaluation</a></span><ul class=\"toc-item\"><li><span><a href=\"#整理测试集\" data-toc-modified-id=\"整理测试集-4.2.3.1\"><span class=\"toc-item-num\">4.2.3.1&nbsp;&nbsp;</span>整理测试集</a></span></li><li><span><a href=\"#计算训练集的流行度\" data-toc-modified-id=\"计算训练集的流行度-4.2.3.2\"><span class=\"toc-item-num\">4.2.3.2&nbsp;&nbsp;</span>计算训练集的流行度</a></span></li><li><span><a href=\"#找出所有商品ID（用于计算覆盖率）\" data-toc-modified-id=\"找出所有商品ID（用于计算覆盖率）-4.2.3.3\"><span class=\"toc-item-num\">4.2.3.3&nbsp;&nbsp;</span>找出所有商品ID（用于计算覆盖率）</a></span></li></ul></li></ul></li><li><span><a href=\"#基于TFIDF的改进\" data-toc-modified-id=\"基于TFIDF的改进-4.3\"><span class=\"toc-item-num\">4.3&nbsp;&nbsp;</span>基于TFIDF的改进</a></span><ul class=\"toc-item\"><li><span><a href=\"#Load-Data\" data-toc-modified-id=\"Load-Data-4.3.1\"><span class=\"toc-item-num\">4.3.1&nbsp;&nbsp;</span>Load Data</a></span></li><li><span><a href=\"#Training\" data-toc-modified-id=\"Training-4.3.2\"><span class=\"toc-item-num\">4.3.2&nbsp;&nbsp;</span>Training</a></span></li><li><span><a href=\"#Evaluation\" data-toc-modified-id=\"Evaluation-4.3.3\"><span class=\"toc-item-num\">4.3.3&nbsp;&nbsp;</span>Evaluation</a></span><ul class=\"toc-item\"><li><span><a href=\"#整理测试集\" data-toc-modified-id=\"整理测试集-4.3.3.1\"><span class=\"toc-item-num\">4.3.3.1&nbsp;&nbsp;</span>整理测试集</a></span></li><li><span><a href=\"#计算训练集的流行度\" data-toc-modified-id=\"计算训练集的流行度-4.3.3.2\"><span class=\"toc-item-num\">4.3.3.2&nbsp;&nbsp;</span>计算训练集的流行度</a></span></li><li><span><a href=\"#找出所有商品（用于计算覆盖率）\" data-toc-modified-id=\"找出所有商品（用于计算覆盖率）-4.3.3.3\"><span class=\"toc-item-num\">4.3.3.3&nbsp;&nbsp;</span>找出所有商品（用于计算覆盖率）</a></span></li></ul></li></ul></li><li><span><a href=\"#TFIDF++\" data-toc-modified-id=\"TFIDF++-4.4\"><span class=\"toc-item-num\">4.4&nbsp;&nbsp;</span>TFIDF++</a></span><ul class=\"toc-item\"><li><span><a href=\"#Load-Data\" data-toc-modified-id=\"Load-Data-4.4.1\"><span class=\"toc-item-num\">4.4.1&nbsp;&nbsp;</span>Load Data</a></span></li><li><span><a href=\"#Training\" data-toc-modified-id=\"Training-4.4.2\"><span class=\"toc-item-num\">4.4.2&nbsp;&nbsp;</span>Training</a></span></li><li><span><a href=\"#Evaluation\" data-toc-modified-id=\"Evaluation-4.4.3\"><span class=\"toc-item-num\">4.4.3&nbsp;&nbsp;</span>Evaluation</a></span><ul class=\"toc-item\"><li><span><a href=\"#整理测试集\" data-toc-modified-id=\"整理测试集-4.4.3.1\"><span class=\"toc-item-num\">4.4.3.1&nbsp;&nbsp;</span>整理测试集</a></span></li><li><span><a href=\"#计算训练集的流行度\" data-toc-modified-id=\"计算训练集的流行度-4.4.3.2\"><span class=\"toc-item-num\">4.4.3.2&nbsp;&nbsp;</span>计算训练集的流行度</a></span></li><li><span><a href=\"#找出所有商品（用于计算覆盖率）\" data-toc-modified-id=\"找出所有商品（用于计算覆盖率）-4.4.3.3\"><span class=\"toc-item-num\">4.4.3.3&nbsp;&nbsp;</span>找出所有商品（用于计算覆盖率）</a></span></li></ul></li></ul></li><li><span><a href=\"#标签的相关性报告\" data-toc-modified-id=\"标签的相关性报告-4.5\"><span class=\"toc-item-num\">4.5&nbsp;&nbsp;</span>标签的相关性报告</a></span></li><li><span><a href=\"#考虑加入标签协同过滤方式\" data-toc-modified-id=\"考虑加入标签协同过滤方式-4.6\"><span class=\"toc-item-num\">4.6&nbsp;&nbsp;</span>考虑加入标签协同过滤方式</a></span><ul class=\"toc-item\"><li><span><a href=\"#Training\" data-toc-modified-id=\"Training-4.6.1\"><span class=\"toc-item-num\">4.6.1&nbsp;&nbsp;</span>Training</a></span></li><li><span><a href=\"#Evaluation\" data-toc-modified-id=\"Evaluation-4.6.2\"><span class=\"toc-item-num\">4.6.2&nbsp;&nbsp;</span>Evaluation</a></span><ul class=\"toc-item\"><li><span><a href=\"#整理测试集\" data-toc-modified-id=\"整理测试集-4.6.2.1\"><span class=\"toc-item-num\">4.6.2.1&nbsp;&nbsp;</span>整理测试集</a></span></li><li><span><a href=\"#计算测试集流行度\" data-toc-modified-id=\"计算测试集流行度-4.6.2.2\"><span class=\"toc-item-num\">4.6.2.2&nbsp;&nbsp;</span>计算测试集流行度</a></span></li><li><span><a href=\"#找出所有商品（用于计算覆盖率）\" data-toc-modified-id=\"找出所有商品（用于计算覆盖率）-4.6.2.3\"><span class=\"toc-item-num\">4.6.2.3&nbsp;&nbsp;</span>找出所有商品（用于计算覆盖率）</a></span></li></ul></li></ul></li></ul></li><li><span><a href=\"#Chapter5\" data-toc-modified-id=\"Chapter5-5\"><span class=\"toc-item-num\">5&nbsp;&nbsp;</span>Chapter5</a></span><ul class=\"toc-item\"><li><span><a href=\"#时间特性\" data-toc-modified-id=\"时间特性-5.1\"><span class=\"toc-item-num\">5.1&nbsp;&nbsp;</span>时间特性</a></span><ul class=\"toc-item\"><li><span><a href=\"#找到打标签最多的商品\" data-toc-modified-id=\"找到打标签最多的商品-5.1.1\"><span class=\"toc-item-num\">5.1.1&nbsp;&nbsp;</span>找到打标签最多的商品</a></span></li><li><span><a href=\"#热度统计\" data-toc-modified-id=\"热度统计-5.1.2\"><span class=\"toc-item-num\">5.1.2&nbsp;&nbsp;</span>热度统计</a></span></li><li><span><a href=\"#画图\" data-toc-modified-id=\"画图-5.1.3\"><span class=\"toc-item-num\">5.1.3&nbsp;&nbsp;</span>画图</a></span></li></ul></li><li><span><a href=\"#最近最热门\" data-toc-modified-id=\"最近最热门-5.2\"><span class=\"toc-item-num\">5.2&nbsp;&nbsp;</span>最近最热门</a></span><ul class=\"toc-item\"><li><span><a href=\"#数据集\" data-toc-modified-id=\"数据集-5.2.1\"><span class=\"toc-item-num\">5.2.1&nbsp;&nbsp;</span>数据集</a></span></li><li><span><a href=\"#模型\" data-toc-modified-id=\"模型-5.2.2\"><span class=\"toc-item-num\">5.2.2&nbsp;&nbsp;</span>模型</a></span></li><li><span><a href=\"#推荐\" data-toc-modified-id=\"推荐-5.2.3\"><span class=\"toc-item-num\">5.2.3&nbsp;&nbsp;</span>推荐</a></span></li></ul></li></ul></li></ul></div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-26T07:20:30.241266Z",
     "start_time": "2018-11-26T07:20:30.238078Z"
    },
    "init_cell": true
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import seaborn as sns\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-10T04:02:25.230968Z",
     "start_time": "2018-06-10T04:02:25.172528Z"
    }
   },
   "source": [
    "# Chapter2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 用户行为分析"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 用户活跃度和物品流行度的分布"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-07T07:41:33.687108Z",
     "start_time": "2018-11-07T07:41:32.167378Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "DataFrame constructor not properly called!",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m-----------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0mTraceback (most recent call last)",
      "\u001b[0;32m<ipython-input-6-dc0c36023e10>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0mmovieLen_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mread_rating_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mmovieLen_df\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDataFrame\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmovieLen_data\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mcolumns\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"userID\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\"movieID\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\"Rating\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      6\u001b[0m \u001b[0mmovieLen_df\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhead\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, data, index, columns, dtype, copy)\u001b[0m\n\u001b[1;32m    420\u001b[0m                                          dtype=values.dtype, copy=False)\n\u001b[1;32m    421\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 422\u001b[0;31m                 \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'DataFrame constructor not properly called!'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    423\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    424\u001b[0m         \u001b[0mNDFrame\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmgr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfastpath\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: DataFrame constructor not properly called!"
     ]
    }
   ],
   "source": [
    "from main.util.movielen_reader import read_rating_data\n",
    "from main.util import movielen_reader\n",
    "\n",
    "movieLen_data = read_rating_data()\n",
    "movieLen_df = pd.DataFrame(movieLen_data,columns = [\"userID\",\"movieID\",\"Rating\"])\n",
    "movieLen_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-10T05:44:57.080548Z",
     "start_time": "2018-06-10T05:44:57.024300Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Item Popularity</th>\n",
       "      <th>counts</th>\n",
       "      <th>log_Item_Popularity</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>114</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2</td>\n",
       "      <td>89</td>\n",
       "      <td>0.301030</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>3</td>\n",
       "      <td>42</td>\n",
       "      <td>0.477121</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4</td>\n",
       "      <td>45</td>\n",
       "      <td>0.602060</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>5</td>\n",
       "      <td>39</td>\n",
       "      <td>0.698970</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   Item Popularity  counts  log_Item_Popularity\n",
       "0                1     114             0.000000\n",
       "1                2      89             0.301030\n",
       "2                3      42             0.477121\n",
       "3                4      45             0.602060\n",
       "4                5      39             0.698970"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum_movie_rating = (\n",
    "    movieLen_df[[\"userID\",\"movieID\"]].groupby([\"movieID\"],as_index = False).count())\n",
    "sum_movie_rating.rename(\n",
    "                mapper = {\"userID\" : \"Item Popularity\"},\n",
    "                axis = 1,\n",
    "                inplace = True\n",
    ")\n",
    "sum_movie_rating = sum_movie_rating.groupby(\"Item Popularity\",as_index = False).count()\n",
    "sum_movie_rating.rename(\n",
    "                mapper = {\"movieID\" : \"counts\"},\n",
    "                axis = 1,\n",
    "                inplace = True\n",
    ")\n",
    "sum_movie_rating[\"log_Item_Popularity\"] = np.log10(sum_movie_rating[\"Item Popularity\"])\n",
    "sum_movie_rating.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-10T05:47:20.319494Z",
     "start_time": "2018-06-10T05:47:19.842931Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib64/python3.6/site-packages/matplotlib/axes/_axes.py:6462: UserWarning: The 'normed' kwarg is deprecated, and has been replaced by the 'density' kwarg.\n",
      "  warnings.warn(\"The 'normed' kwarg is deprecated, and has been \"\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAasAAAGoCAYAAAD4hcrDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3Xt8VOWdx/HvMEkg3EFDIpGychFSRESggFYooSGUCISbLSprtZTVVRDRdEFXtKxcBFFq1bZ52VrqbVXARG4GSazgBZQYEDSgXUUlkMSShEBIYDKZ/QMzzWUmmZlkZp5MPu+/zJkz5/zmxMmX5znPeR6Lw+FwCAAAg7UJdgEAADSGsAIAGI+wAgAYj7ACABiPsAIAGK9VhdXRo0eDXYJbJtcmUV9TUV/TUB9aVViVl5cHuwS3TK5Nor6mor6moT60qrACALRMYcEuAEDL8dLebxrd58aRPwhAJWhtCCsAzYpAgz/QDQgAMB4tKwABR+sL3iKsABipZqCdyC9VTqnrgCPUWge6AQEAxiOsAADGoxsQgCTP7iMBwULLCgBgPMIKAGA8wgoAYDzCCgBgPMIKAGA8wgoAYDzCCgBgPMIKAGA8HgoGWoHGHvg9kV+qS2I6BKgawHu0rAAAxiOsAADGI6wAAMYjrAAAxiOsAADGI6wAAMZj6DrQwrX2dag8+fw3jvxBACqBP9GyAgAYj7ACABiPsAIAGI+wAgAYj7ACABiPsAIAGI+h64DBWvuwdKAaLSsAgPEIKwCA8QgrAIDxCCsAgPEYYAEECYMnAM/RsgIAGI+WFYCQx8zsLR8tKwCA8WhZAc3M1b/iT+SXKqeUe1SArwgrABBdhaajGxAAYDxaVoAXGG4OBActKwCA8WhZAd+j1QSYi5YVAMB4tKzQKtBqAlo2wgot3kt7v+E5JiDEEVYwGi0imMTd/481/7HEs1j+QVghaAgiAJ4irOA1QgZAoLWqsNr2eeP3NTxpwjfXtCw1j2P6PRfT6wMQ2iwOh8MR7CK8kZ2dHewSAMBvhg0bFuwSjNTiwgoA0PrwUDAAwHiEFQDAeIQVAMB4hBUAwHiEFQDAeIQVAMB4hBUAwHiEFQDAeIQVAMB4LS6smjLd0tGjR5uvkGZmcm0S9TUV9TUN9dXX2qaea3Fh1RTl5eXBLsEtk2uTqK+pqK9pqA+tKqwAAC0TYQUAMB5hBQAwHmEFADAeYQUAMB5hBQAwHmEFADAeYQUAMF5YsAsAEFgOh0PLly/XO++8o3bt2mnVqlVq06b2v1vPnDmjm266yflzfn6+pkyZogceeECStG3bNj311FOyWCwaOHCg1q5dG9DPIElPPPGE0tLSVFpaqpycHJf7FBcXa8GCBTp06JCmTZumpUuXen2eX/3qVzpw4ICGDRumP/3pT87tN954o8rKyiRJBQUFuvrqq/XMM89o586d+t3vfqc2bdrIarXq/vvv1/Dhw337kHBqFWGVlpOnNRlHdLykXD27nlBK4gAlD40NdlkIQZWVlQoLa/6vld1ul9VqbZZj7dq1S0ePHtWOHTt04MABPfzww1q2bFmtfTp27Kj09HTnz9OnT9eECRMkXZhaKDU1VS+//LK6dOmikydPNktd3ho3bpxuuukmJSYmut2nbdu2uvvuu/XFF1/oiy++8Ok8c+fOVXl5uV555ZVa21966SXnf99yyy3O6zN69GiNHz9eFotFhw8f1sKFC/Xmm2/6dG78S8iHVVpOnpZsOqhym12SlFdSriWbDkoSgdWKHTt2THPnztWgQYP02WefqX///nr00UcVGRmpQ4cOadWqVTp79qy6deumlStXqkePHnr11Vf1yiuvyGazqXfv3lq9erUiIyO1ePFiRUREKDc3V1dffbXGjx+v5cuXS5IsFoteeOEFORwOPfroo9q9e7csFovuuOMOTZo0SXv37tVTTz2lbt266fPPP9egQYP02GOPyWKxKD4+Xj/72c/0/vvva+7cuUpKSmqWz56Zmank5GRZLBZdddVVKi0tVVFRkdv9v/rqK508edLZOnj11Vd10003qUuXLpKkiy66yLnv1KlTa4Vctfj4eE2cOFG7d+9W27ZttXbtWvXu3btJn+Oqq65qdJ/27dtr+PDh+uabb+q99u677+r3v/+9zp8/r169emnlypXq0KFDvf1Gjx6tvXv3uj3HmTNndPDgQT399NOSVOsY5eXlslgsnnwcNCLkw2pNxhFnUFUrt9m1JuMIYdXKffXVV1q+fLmGDRumJUuW6KWXXtK///u/65FHHtEzzzyj7t27a9u2bXriiSe0cuVKJSQk6IYbbpB0oQtqw4YNmjNnjqQL3UD/+7//K6vVqttvv11Lly7VsGHDVFZWprZt2+qDDz7Q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ABCaPAqrlJQUffvttxo4cKCsVqukC60fX8IqKipKMTEx+vLLL9WnTx998MEH6tu3r/r27au0tDTNmzdPaWlpGj9+vNfHBgCEJo/C6tChQ9q2bVuDXXPeePDBB3XffffJZrOpV69eWrlypaqqqrRw4UJt2LBBPXv21Lp165rlXACAls+jsOrfv7++++479ejRo1lOGhcXp02bNtXbvn79+mY5PgAgtHgUVsXFxUpKStKVV16p8PBw5/Y//vGPfisMAIBqHoXV/Pnz/V0HAABueRRWP/rRj/xdBwAAbnkUVkOHDnUOrrDZbKqsrFRkZKQ+/vhjvxYHAIDkYVjl5OQ4/9vhcCgzM1P79+/3W1EAANTk9TofFotFP/3pT1kpGAAQMB61rHbs2OH876qqKh06dEht27b1W1EAANTkUVi9/fbbzv+2Wq2KjY3VM88847eiAACoyaOwasraVQAANJVH96zy8/N15513avTo0Ro9erTmz5+v/Px8f9cGAIAkD8NqyZIlio+P1+7du7V7926NGzdOS5Ys8XdtAABI8jCsioqKNGPGDIWFhSksLEzTp09XUVGRv2sDAECSh2HVtWtXpaeny263y263Kz09XV27dvV3bQAASPIwrFasWKHt27fr2muv1Y9//GNlZGRo1apV/q4NAABJHo4GfPLJJ/Xoo4+qS5cukqSSkhI9+uijjBIEAASERy2rI0eOOINKutAtmJub67eiAACoyaOwqqqq0qlTp5w/l5SUyG63+60oAABq8qgb8LbbbtPPf/5zTZw4UZL05ptv6vbbb/drYQAAVPMorJKTk3XFFVdoz549kqSnnnpK/fr182thAABU8yisJKlfv34EFAAgKLxeIgQAgEAjrAAAxiOsAADGI6wAAMYjrAAAxiOsAADGI6wAAMYjrAAAxiOsAADG83gGCwRPWk6e1mQc0fGScvXsGqmUxAFKHhob7LIAIGAIK8Ol5eRpyaaDKrddmOU+r6RcSzYdlCQCC0CrQTeg4dZkHHEGVbVym11rMo4EqSIACDzCynDHS8q92g4AoYiwMlzPrpFebQeAUERYGS4lcYAiw621tkWGW5WSOCBIFQFA4DHAwnDVgygYDQigNSOsWoDkobGEE4BWjbAKoprPT0V1CNP913cmlADABcIqSOo+P1VYVsnzUwDgBgMsgoTnpwDAc4RVkPD8FAB4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\n",
      "text/plain": [
       "<Figure size 432x432 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import seaborn as sns\n",
    "\n",
    "sns.set_style(\"whitegrid\")\n",
    "axe = sns.jointplot(x = \"log_Item_Popularity\",y = \"counts\",data = sum_movie_rating)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-11T04:29:07.358237Z",
     "start_time": "2018-06-11T04:29:06.871242Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib64/python3.6/site-packages/matplotlib/axes/_axes.py:6462: UserWarning: The 'normed' kwarg is deprecated, and has been replaced by the 'density' kwarg.\n",
      "  warnings.warn(\"The 'normed' kwarg is deprecated, and has been \"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Text(0.5,1,'')"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x432 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import seaborn as sns\n",
    "\n",
    "item_popularity = movieLen_df.groupby([\"userID\"],as_index = False).count()\n",
    "item_popularity.rename(mapper = {\"movieID\" : \"movie_count\"},axis = 1,inplace = True)\n",
    "item_popularity = item_popularity.groupby([\"movie_count\"],as_index = False).count()\n",
    "item_popularity.rename(mapper = {\"userID\" : \"user_count\"},axis = 1,inplace = True)\n",
    "item_popularity[\"log_movie_count\"] = np.log10(item_popularity.movie_count)\n",
    "\n",
    "sns.set_style(\"whitegrid\")\n",
    "\n",
    "sns.jointplot(data = item_popularity,x = \"log_movie_count\",y = \"user_count\")\n",
    "plt.title(\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 用户活跃度和物品流行度的关系"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-11T05:05:35.850023Z",
     "start_time": "2018-06-11T05:05:35.073281Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib64/python3.6/site-packages/matplotlib/axes/_axes.py:6462: UserWarning: The 'normed' kwarg is deprecated, and has been replaced by the 'density' kwarg.\n",
      "  warnings.warn(\"The 'normed' kwarg is deprecated, and has been \"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<seaborn.axisgrid.JointGrid at 0x7fb9a9645550>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x432 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import seaborn as sns\n",
    "\n",
    "user_activity = movieLen_df[[\"userID\",\"movieID\"]].groupby(\"userID\").count()\n",
    "user_activity.rename({\"movieID\" : \"user_activity\"},axis = 1,inplace = True)\n",
    "\n",
    "movie_popularity = (movieLen_df[[\"userID\",\"movieID\"]].\n",
    "                                groupby(\"movieID\",as_index = False).count())\n",
    "movie_popularity.rename({\"userID\" : \"movie_popularity\"},axis = 1,inplace = True)\n",
    "\n",
    "\n",
    "combine = pd.merge(left = movieLen_df,right = user_activity,on = \"userID\")\n",
    "combine = pd.merge(left = combine,right = movie_popularity,on = \"movieID\")\n",
    "\n",
    "combine = combine.groupby([\"user_activity\"],as_index = False).mean()\n",
    "\n",
    "sns.set_style(\"whitegrid\")\n",
    "sns.jointplot(data = combine,x = \"user_activity\",y = \"movie_popularity\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于邻域方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ＵSERCF"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-14T05:01:40.254968Z",
     "start_time": "2018-06-14T05:01:37.884374Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.chapter2 import usercf\n",
    "from main.util import movielen_reader\n",
    "\n",
    "trainset,testset = movielen_reader.read_rating_data(train_rate = 0.8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Training "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-14T05:01:53.452768Z",
     "start_time": "2018-06-14T05:01:44.188876Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "开始训练模型\n",
      "开始载入用户协同矩阵....\n",
      "载入协同过滤矩阵完成\n",
      "开始保存协同过滤矩阵\n",
      "保存协同过滤矩阵完成\n"
     ]
    }
   ],
   "source": [
    "uf = usercf.UserCF()\n",
    "uf.train(trainset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-14T05:01:57.785442Z",
     "start_time": "2018-06-14T05:01:57.649044Z"
    }
   },
   "outputs": [],
   "source": [
    "test = dict()\n",
    "for user,item,_ in testset:\n",
    "    test.setdefault(user,list())\n",
    "    test[user].append(item)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-14T05:02:02.144210Z",
     "start_time": "2018-06-14T05:02:02.134979Z"
    }
   },
   "outputs": [],
   "source": [
    "def train_popularity(train):\n",
    "    \"\"\"计算训练集的流行度\"\"\"\n",
    "    train_popularity = dict()\n",
    "    for user,item,_ in train:\n",
    "        train_popularity.setdefault(item,0)\n",
    "        train_popularity[item] += 1\n",
    "    return train_popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-14T05:02:06.837889Z",
     "start_time": "2018-06-14T05:02:06.727612Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util import metric\n",
    "from main.util import movielen_reader\n",
    "import pandas as pd\n",
    "\n",
    "def evaluate(N,K):\n",
    "    \"\"\"评价模型\n",
    "        Args:\n",
    "            N:　　　　推荐的商品个数\n",
    "            K:　　　　搜索邻近的用户个数\n",
    "        Return:\n",
    "            精确率,召回率,覆盖率,流行度\n",
    "    \"\"\"\n",
    "    recommens = uf.recommend_users(test.keys(),N = N,K = K)\n",
    "    all_items = movielen_reader.all_items()\n",
    "    item_popularity = train_popularity(trainset)\n",
    "\n",
    "    recall = metric.recall(recommends = recommens,tests=test)\n",
    "    precision = metric.precision(recommends = recommens,tests = test)\n",
    "    coverage = metric.coverage(recommends = recommens,all_items = all_items)\n",
    "    popularity = metric.popularity(item_popular = item_popularity,recommends = recommens)\n",
    "    \n",
    "    return precision,recall,coverage,popularity\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-14T05:05:57.577139Z",
     "start_time": "2018-06-14T05:02:11.008311Z"
    }
   },
   "outputs": [],
   "source": [
    "N = 30   #表示推荐的商品个数\n",
    "K_list = [5,10,20,40,80,160]  #表示临近用户的list\n",
    "evals = list()\n",
    "\n",
    "for k in K_list:\n",
    "    single_eval = evaluate(N = N,K = k)\n",
    "    evals.append(single_eval)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-14T05:14:16.786880Z",
     "start_time": "2018-06-14T05:14:16.553702Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Precision</th>\n",
       "      <th>Recall</th>\n",
       "      <th>Coverage</th>\n",
       "      <th>Popularity</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.187374</td>\n",
       "      <td>0.206607</td>\n",
       "      <td>0.709120</td>\n",
       "      <td>6.571688</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>0.215727</td>\n",
       "      <td>0.237871</td>\n",
       "      <td>0.576902</td>\n",
       "      <td>6.727978</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>0.234815</td>\n",
       "      <td>0.258917</td>\n",
       "      <td>0.469239</td>\n",
       "      <td>6.844714</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40</th>\n",
       "      <td>0.244026</td>\n",
       "      <td>0.269073</td>\n",
       "      <td>0.389099</td>\n",
       "      <td>6.941994</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>80</th>\n",
       "      <td>0.244296</td>\n",
       "      <td>0.269371</td>\n",
       "      <td>0.310847</td>\n",
       "      <td>7.028955</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>160</th>\n",
       "      <td>0.237698</td>\n",
       "      <td>0.262096</td>\n",
       "      <td>0.246087</td>\n",
       "      <td>7.112617</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     Precision    Recall  Coverage  Popularity\n",
       "5     0.187374  0.206607  0.709120    6.571688\n",
       "10    0.215727  0.237871  0.576902    6.727978\n",
       "20    0.234815  0.258917  0.469239    6.844714\n",
       "40    0.244026  0.269073  0.389099    6.941994\n",
       "80    0.244296  0.269371  0.310847    7.028955\n",
       "160   0.237698  0.262096  0.246087    7.112617"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.DataFrame(\n",
    "        data = evals,\n",
    "        index = K_list,\n",
    "        columns = [\"Precision\",\"Recall\",\"Coverage\",\"Popularity\"]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### USER-IIF"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "USER-IIF在UserCF的基础上考虑了物品的流行度，触使算法推荐比较冷门的物品，相似度：\n",
    "$$w_{uv}=\n",
    "\\frac{\\sum_{i\\in{N(u)\\bigcap{N(v)}}}{\\frac{1}{log(1 + |N(i)|)}}}\n",
    "{\\sqrt{|N(u)||N(v)|}}$$\n",
    "\n",
    "物品的流行度越大，惩罚的力度越大"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-15T11:29:27.588340Z",
     "start_time": "2018-06-15T11:29:25.232789Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.chapter2 import useriif\n",
    "from imp import reload\n",
    "from main.util import movielen_reader\n",
    "\n",
    "trainset,testset = movielen_reader.read_rating_data(train_rate = 0.8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-15T11:29:42.774628Z",
     "start_time": "2018-06-15T11:29:33.608982Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "开始训练模型\n",
      "开始载入用户协同矩阵....\n",
      "载入协同过滤矩阵完成\n",
      "开始保存协同过滤矩阵\n",
      "保存协同过滤矩阵完成\n"
     ]
    }
   ],
   "source": [
    "user_iif = useriif.UserIIF()\n",
    "user_iif.train(trainset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-15T11:30:27.513547Z",
     "start_time": "2018-06-15T11:30:27.376203Z"
    }
   },
   "outputs": [],
   "source": [
    "test = dict()\n",
    "for user,item,_ in testset:\n",
    "    test.setdefault(user,list())\n",
    "    test[user].append(item)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-15T11:30:28.456404Z",
     "start_time": "2018-06-15T11:30:28.453024Z"
    }
   },
   "outputs": [],
   "source": [
    "def train_popularity(train):\n",
    "    \"\"\"计算训练集的流行度\"\"\"\n",
    "    train_popularity = dict()\n",
    "    for user,item,_ in train:\n",
    "        train_popularity.setdefault(item,0)\n",
    "        train_popularity[item] += 1\n",
    "    return train_popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-15T11:30:29.456042Z",
     "start_time": "2018-06-15T11:30:29.451844Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util import metric\n",
    "from main.util import movielen_reader\n",
    "import pandas as pd\n",
    "\n",
    "def evaluate(N,K):\n",
    "    \"\"\"评价模型\n",
    "        Args:\n",
    "            N:　　　　推荐的商品个数\n",
    "            K:　　　　搜索邻近的用户个数\n",
    "        Return:\n",
    "            精确率,召回率,覆盖率,流行度\n",
    "    \"\"\"\n",
    "    recommens = user_iif.recommend_users(test.keys(),N = N,K = K)\n",
    "    all_items = movielen_reader.all_items()\n",
    "    item_popularity = train_popularity(trainset)\n",
    "\n",
    "    recall = metric.recall(recommends = recommens,tests=test)\n",
    "    precision = metric.precision(recommends = recommens,tests = test)\n",
    "    coverage = metric.coverage(recommends = recommens,all_items = all_items)\n",
    "    popularity = metric.popularity(item_popular = item_popularity,recommends = recommens)\n",
    "    \n",
    "    return precision,recall,coverage,popularity\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-15T11:34:19.215737Z",
     "start_time": "2018-06-15T11:30:30.360259Z"
    }
   },
   "outputs": [],
   "source": [
    "N = 30   #表示推荐的商品个数\n",
    "K_list = [5,10,20,40,80,160]  #表示临近用户的list\n",
    "evals = list()\n",
    "\n",
    "for k in K_list:\n",
    "    single_eval = evaluate(N = N,K = k)\n",
    "    evals.append(single_eval)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-15T11:35:44.571572Z",
     "start_time": "2018-06-15T11:35:44.372938Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Precision</th>\n",
       "      <th>Recall</th>\n",
       "      <th>Coverage</th>\n",
       "      <th>Popularity</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.182898</td>\n",
       "      <td>0.201248</td>\n",
       "      <td>0.730977</td>\n",
       "      <td>6.516392</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>0.211873</td>\n",
       "      <td>0.233129</td>\n",
       "      <td>0.586077</td>\n",
       "      <td>6.676015</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>0.232868</td>\n",
       "      <td>0.256231</td>\n",
       "      <td>0.486239</td>\n",
       "      <td>6.800656</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40</th>\n",
       "      <td>0.243602</td>\n",
       "      <td>0.268042</td>\n",
       "      <td>0.409336</td>\n",
       "      <td>6.904974</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>80</th>\n",
       "      <td>0.245730</td>\n",
       "      <td>0.270383</td>\n",
       "      <td>0.331624</td>\n",
       "      <td>7.000024</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>160</th>\n",
       "      <td>0.240250</td>\n",
       "      <td>0.264353</td>\n",
       "      <td>0.260119</td>\n",
       "      <td>7.091465</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     Precision    Recall  Coverage  Popularity\n",
       "5     0.182898  0.201248  0.730977    6.516392\n",
       "10    0.211873  0.233129  0.586077    6.676015\n",
       "20    0.232868  0.256231  0.486239    6.800656\n",
       "40    0.243602  0.268042  0.409336    6.904974\n",
       "80    0.245730  0.270383  0.331624    7.000024\n",
       "160   0.240250  0.264353  0.260119    7.091465"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.DataFrame(\n",
    "        data = evals,\n",
    "        index = K_list,\n",
    "        columns = [\"Precision\",\"Recall\",\"Coverage\",\"Popularity\"]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ITEMCF"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-24T04:57:59.584902Z",
     "start_time": "2018-06-24T04:57:57.393380Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.chapter2 import itemcf\n",
    "from imp import reload\n",
    "from main.util import movielen_reader\n",
    "reload(itemcf)\n",
    "reload(movielen_reader)\n",
    "\n",
    "trainset,testset = movielen_reader.read_rating_data(train_rate = 0.8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-24T04:58:13.410432Z",
     "start_time": "2018-06-24T04:58:01.175578Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "开始训练模型\n",
      "开始载入用户协同矩阵....\n",
      "载入协同过滤矩阵完成\n",
      "开始保存协同过滤矩阵\n",
      "IOPub data rate exceeded.\n",
      "The notebook server will temporarily stop sending output\n",
      "to the client in order to avoid crashing it.\n",
      "To change this limit, set the config variable\n",
      "`--NotebookApp.iopub_data_rate_limit`.\n",
      "\n",
      "Current values:\n",
      "NotebookApp.iopub_data_rate_limit=1000000.0 (bytes/sec)\n",
      "NotebookApp.rate_limit_window=3.0 (secs)\n",
      "\n",
      "保存协同过滤矩阵完成\n"
     ]
    }
   ],
   "source": [
    "item_cf = itemcf.ItemCF()\n",
    "item_cf.train(trainset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-24T04:58:55.847783Z",
     "start_time": "2018-06-24T04:58:55.712433Z"
    }
   },
   "outputs": [],
   "source": [
    "test = dict()\n",
    "for user,item,_ in testset:\n",
    "    test.setdefault(user,list())\n",
    "    test[user].append(item)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-24T04:58:56.539084Z",
     "start_time": "2018-06-24T04:58:56.535693Z"
    }
   },
   "outputs": [],
   "source": [
    "def train_popularity(train):\n",
    "    \"\"\"计算训练集的流行度\"\"\"\n",
    "    train_popularity = dict()\n",
    "    for user,item,_ in train:\n",
    "        train_popularity.setdefault(item,0)\n",
    "        train_popularity[item] += 1\n",
    "    return train_popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-24T04:59:01.807657Z",
     "start_time": "2018-06-24T04:59:01.763366Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util import metric\n",
    "from main.util import movielen_reader\n",
    "import pandas as pd\n",
    "\n",
    "def evaluate(N,K):\n",
    "    \"\"\"评价模型\n",
    "        Args:\n",
    "            N:　　　　推荐的商品个数\n",
    "            K:　　　　搜索邻近的用户个数\n",
    "        Return:\n",
    "            精确率,召回率,覆盖率,流行度\n",
    "    \"\"\"\n",
    "    recommens = item_cf.recommend_users(test.keys(),N = N,K = K)\n",
    "    all_items = movielen_reader.all_items()\n",
    "    item_popularity = train_popularity(trainset)\n",
    "\n",
    "    recall = metric.recall(recommends = recommens,tests=test)\n",
    "    precision = metric.precision(recommends = recommens,tests = test)\n",
    "    coverage = metric.coverage(recommends = recommens,all_items = all_items)\n",
    "    popularity = metric.popularity(item_popular = item_popularity,recommends = recommens)\n",
    "    \n",
    "    return precision,recall,coverage,popularity\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-24T06:53:02.939197Z",
     "start_time": "2018-06-24T05:18:24.156073Z"
    }
   },
   "outputs": [],
   "source": [
    "N = 30   #表示推荐的商品个数\n",
    "K_list = [5,10,20,40,80,160]  #表示临近用户的list\n",
    "evals = list()\n",
    "\n",
    "for k in K_list:\n",
    "    single_eval = evaluate(N = N,K = k)\n",
    "    evals.append(single_eval)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-24T06:54:09.583024Z",
     "start_time": "2018-06-24T06:54:09.296685Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Precision</th>\n",
       "      <th>Recall</th>\n",
       "      <th>Coverage</th>\n",
       "      <th>Popularity</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.189918</td>\n",
       "      <td>0.209924</td>\n",
       "      <td>0.399622</td>\n",
       "      <td>6.890241</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>0.198071</td>\n",
       "      <td>0.218936</td>\n",
       "      <td>0.358877</td>\n",
       "      <td>6.994376</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>0.196668</td>\n",
       "      <td>0.217385</td>\n",
       "      <td>0.297086</td>\n",
       "      <td>7.091567</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40</th>\n",
       "      <td>0.191731</td>\n",
       "      <td>0.211928</td>\n",
       "      <td>0.259039</td>\n",
       "      <td>7.167786</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>80</th>\n",
       "      <td>0.181504</td>\n",
       "      <td>0.200624</td>\n",
       "      <td>0.230167</td>\n",
       "      <td>7.212047</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>160</th>\n",
       "      <td>0.170203</td>\n",
       "      <td>0.188132</td>\n",
       "      <td>0.190502</td>\n",
       "      <td>7.212751</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     Precision    Recall  Coverage  Popularity\n",
       "5     0.189918  0.209924  0.399622    6.890241\n",
       "10    0.198071  0.218936  0.358877    6.994376\n",
       "20    0.196668  0.217385  0.297086    7.091567\n",
       "40    0.191731  0.211928  0.259039    7.167786\n",
       "80    0.181504  0.200624  0.230167    7.212047\n",
       "160   0.170203  0.188132  0.190502    7.212751"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.DataFrame(\n",
    "        data = evals,\n",
    "        index = K_list,\n",
    "        columns = [\"Precision\",\"Recall\",\"Coverage\",\"Popularity\"]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ITEMCF-IUF"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-28T04:05:17.479956Z",
     "start_time": "2018-06-28T04:05:15.224464Z"
    }
   },
   "outputs": [],
   "source": [
    "from imp import reload\n",
    "from main.util import movielen_reader\n",
    "\n",
    "trainset,testset = movielen_reader.read_rating_data(train_rate = 0.8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Train Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-28T04:10:07.625702Z",
     "start_time": "2018-06-28T04:06:20.030071Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "开始训练模型\n",
      "开始载入用户协同矩阵....\n",
      "载入用户协同过滤矩阵失败，重新计算协同过滤矩阵\n",
      "开始保存协同过滤矩阵\n",
      "IOPub data rate exceeded.\n",
      "The notebook server will temporarily stop sending output\n",
      "to the client in order to avoid crashing it.\n",
      "To change this limit, set the config variable\n",
      "`--NotebookApp.iopub_data_rate_limit`.\n",
      "\n",
      "Current values:\n",
      "NotebookApp.iopub_data_rate_limit=1000000.0 (bytes/sec)\n",
      "NotebookApp.rate_limit_window=3.0 (secs)\n",
      "\n",
      "保存协同过滤矩阵完成\n"
     ]
    }
   ],
   "source": [
    "from main.chapter2 import itemiuf\n",
    "\n",
    "item_iuf = itemiuf.ItemIUF()\n",
    "item_iuf.train(trainset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-28T04:10:09.043722Z",
     "start_time": "2018-06-28T04:10:08.888442Z"
    }
   },
   "outputs": [],
   "source": [
    "test = dict()\n",
    "for user,item,_ in testset:\n",
    "    test.setdefault(user,list())\n",
    "    test[user].append(item)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-28T04:10:10.217420Z",
     "start_time": "2018-06-28T04:10:10.214946Z"
    }
   },
   "outputs": [],
   "source": [
    "def train_popularity(train):\n",
    "    \"\"\"计算训练集的流行度\"\"\"\n",
    "    train_popularity = dict()\n",
    "    for user,item,_ in train:\n",
    "        train_popularity.setdefault(item,0)\n",
    "        train_popularity[item] += 1\n",
    "    return train_popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-28T04:10:11.307811Z",
     "start_time": "2018-06-28T04:10:11.271754Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util import metric\n",
    "from main.util import movielen_reader\n",
    "import pandas as pd\n",
    "\n",
    "def evaluate(N,K):\n",
    "    \"\"\"评价模型\n",
    "        Args:\n",
    "            N:　　　　推荐的商品个数\n",
    "            K:　　　　搜索邻近的用户个数\n",
    "        Return:\n",
    "            精确率,召回率,覆盖率,流行度\n",
    "    \"\"\"\n",
    "    recommens = item_iuf.recommend_users(test.keys(),N = N,K = K)\n",
    "    all_items = movielen_reader.all_items()\n",
    "    item_popularity = train_popularity(trainset)\n",
    "\n",
    "    recall = metric.recall(recommends = recommens,tests=test)\n",
    "    precision = metric.precision(recommends = recommens,tests = test)\n",
    "    coverage = metric.coverage(recommends = recommens,all_items = all_items)\n",
    "    popularity = metric.popularity(item_popular = item_popularity,recommends = recommens)\n",
    "    \n",
    "    return precision,recall,coverage,popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-28T06:06:46.794630Z",
     "start_time": "2018-06-28T04:11:06.302229Z"
    }
   },
   "outputs": [],
   "source": [
    "N = 30   #表示推荐的商品个数\n",
    "K_list = [5,10,20,40,80,160]  #表示临近用户的list\n",
    "evals = list()\n",
    "\n",
    "for k in K_list:\n",
    "    single_eval = evaluate(N = N,K = k)\n",
    "    evals.append(single_eval)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-28T06:08:25.038178Z",
     "start_time": "2018-06-28T06:08:24.636614Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Precision</th>\n",
       "      <th>Recall</th>\n",
       "      <th>Coverage</th>\n",
       "      <th>Popularity</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.195344</td>\n",
       "      <td>0.215921</td>\n",
       "      <td>0.385591</td>\n",
       "      <td>6.962440</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>0.201664</td>\n",
       "      <td>0.222907</td>\n",
       "      <td>0.339450</td>\n",
       "      <td>7.066032</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>0.198761</td>\n",
       "      <td>0.219698</td>\n",
       "      <td>0.279547</td>\n",
       "      <td>7.158352</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40</th>\n",
       "      <td>0.193180</td>\n",
       "      <td>0.213530</td>\n",
       "      <td>0.245278</td>\n",
       "      <td>7.228507</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>80</th>\n",
       "      <td>0.183558</td>\n",
       "      <td>0.202894</td>\n",
       "      <td>0.216945</td>\n",
       "      <td>7.269082</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>160</th>\n",
       "      <td>0.174235</td>\n",
       "      <td>0.192589</td>\n",
       "      <td>0.186185</td>\n",
       "      <td>7.276031</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     Precision    Recall  Coverage  Popularity\n",
       "5     0.195344  0.215921  0.385591    6.962440\n",
       "10    0.201664  0.222907  0.339450    7.066032\n",
       "20    0.198761  0.219698  0.279547    7.158352\n",
       "40    0.193180  0.213530  0.245278    7.228507\n",
       "80    0.183558  0.202894  0.216945    7.269082\n",
       "160   0.174235  0.192589  0.186185    7.276031"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.DataFrame(\n",
    "        data = evals,\n",
    "        index = K_list,\n",
    "        columns = [\"Precision\",\"Recall\",\"Coverage\",\"Popularity\"]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ITEMCF-NORM"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-29T06:02:44.340866Z",
     "start_time": "2018-06-29T06:02:42.180519Z"
    }
   },
   "outputs": [],
   "source": [
    "from imp import reload\n",
    "from main.util import movielen_reader\n",
    "\n",
    "trainset,testset = movielen_reader.read_rating_data(train_rate = 0.8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Train Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-29T06:05:56.824983Z",
     "start_time": "2018-06-29T06:03:29.076731Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "开始训练模型\n",
      "开始载入用户协同矩阵....\n",
      "载入用户协同过滤矩阵失败，重新计算协同过滤矩阵\n",
      "开始保存协同过滤矩阵\n",
      "IOPub data rate exceeded.\n",
      "The notebook server will temporarily stop sending output\n",
      "to the client in order to avoid crashing it.\n",
      "To change this limit, set the config variable\n",
      "`--NotebookApp.iopub_data_rate_limit`.\n",
      "\n",
      "Current values:\n",
      "NotebookApp.iopub_data_rate_limit=1000000.0 (bytes/sec)\n",
      "NotebookApp.rate_limit_window=3.0 (secs)\n",
      "\n",
      "保存协同过滤矩阵完成\n"
     ]
    }
   ],
   "source": [
    "from main.chapter2 import itemnorm\n",
    "\n",
    "item_norm = itemnorm.ItemNorm()\n",
    "item_norm.train(trainset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-29T06:29:08.439586Z",
     "start_time": "2018-06-29T06:29:08.297597Z"
    }
   },
   "outputs": [],
   "source": [
    "test = dict()\n",
    "for user,item,_ in testset:\n",
    "    test.setdefault(user,list())\n",
    "    test[user].append(item)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-29T06:29:09.430942Z",
     "start_time": "2018-06-29T06:29:09.426925Z"
    }
   },
   "outputs": [],
   "source": [
    "def train_popularity(train):\n",
    "    \"\"\"计算训练集的流行度\"\"\"\n",
    "    train_popularity = dict()\n",
    "    for user,item,_ in train:\n",
    "        train_popularity.setdefault(item,0)\n",
    "        train_popularity[item] += 1\n",
    "    return train_popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-29T06:29:18.491211Z",
     "start_time": "2018-06-29T06:29:18.467304Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util import metric\n",
    "from main.util import movielen_reader\n",
    "import pandas as pd\n",
    "\n",
    "def evaluate(N,K):\n",
    "    \"\"\"评价模型\n",
    "        Args:\n",
    "            N:　　　　推荐的商品个数\n",
    "            K:　　　　搜索邻近的用户个数\n",
    "        Return:\n",
    "            精确率,召回率,覆盖率,流行度\n",
    "    \"\"\"\n",
    "    recommens = item_norm.recommend_users(test.keys(),N = N,K = K)\n",
    "    all_items = movielen_reader.all_items()\n",
    "    item_popularity = train_popularity(trainset)\n",
    "\n",
    "    recall = metric.recall(recommends = recommens,tests=test)\n",
    "    precision = metric.precision(recommends = recommens,tests = test)\n",
    "    coverage = metric.coverage(recommends = recommens,all_items = all_items)\n",
    "    popularity = metric.popularity(item_popular = item_popularity,recommends = recommens)\n",
    "    \n",
    "    return precision,recall,coverage,popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-29T08:04:23.103934Z",
     "start_time": "2018-06-29T06:29:19.630960Z"
    }
   },
   "outputs": [],
   "source": [
    "N = 30   #表示推荐的商品个数\n",
    "K_list = [5,10,20,40,80,160]  #表示临近用户的list\n",
    "evals = list()\n",
    "\n",
    "for k in K_list:\n",
    "    single_eval = evaluate(N = N,K = k)\n",
    "    evals.append(single_eval)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-06-29T08:53:33.162295Z",
     "start_time": "2018-06-29T08:53:32.914236Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Precision</th>\n",
       "      <th>Recall</th>\n",
       "      <th>Coverage</th>\n",
       "      <th>Popularity</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.189918</td>\n",
       "      <td>0.209924</td>\n",
       "      <td>0.399622</td>\n",
       "      <td>6.890218</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>0.198071</td>\n",
       "      <td>0.218936</td>\n",
       "      <td>0.359147</td>\n",
       "      <td>6.994348</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>0.196668</td>\n",
       "      <td>0.217385</td>\n",
       "      <td>0.297086</td>\n",
       "      <td>7.091567</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40</th>\n",
       "      <td>0.191731</td>\n",
       "      <td>0.211928</td>\n",
       "      <td>0.259039</td>\n",
       "      <td>7.167786</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>80</th>\n",
       "      <td>0.181504</td>\n",
       "      <td>0.200624</td>\n",
       "      <td>0.230167</td>\n",
       "      <td>7.212047</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>160</th>\n",
       "      <td>0.170203</td>\n",
       "      <td>0.188132</td>\n",
       "      <td>0.190502</td>\n",
       "      <td>7.212751</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     Precision    Recall  Coverage  Popularity\n",
       "5     0.189918  0.209924  0.399622    6.890218\n",
       "10    0.198071  0.218936  0.359147    6.994348\n",
       "20    0.196668  0.217385  0.297086    7.091567\n",
       "40    0.191731  0.211928  0.259039    7.167786\n",
       "80    0.181504  0.200624  0.230167    7.212047\n",
       "160   0.170203  0.188132  0.190502    7.212751"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.DataFrame(\n",
    "        data = evals,\n",
    "        index = K_list,\n",
    "        columns = [\"Precision\",\"Recall\",\"Coverage\",\"Popularity\"]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Chapter3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Chapter4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 标签流行度长尾趋势"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T06:35:45.703025Z",
     "start_time": "2018-11-08T06:35:44.747941Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "437593"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from main.util import delicious_reader\n",
    "\n",
    "delicious_path = \"data/delicious-2k/user_taggedbookmarks-timestamps.dat\"\n",
    "\n",
    "data, _ = delicious_reader.split_data(filename=delicious_path, cv_folder=10,k=20)\n",
    "len(data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-02T05:59:27.794886Z",
     "start_time": "2018-11-02T05:59:27.668724Z"
    }
   },
   "outputs": [],
   "source": [
    "from collections import defaultdict\n",
    "\n",
    "tags = defaultdict(lambda : 0)\n",
    "\n",
    "for user_id, bookmark_id, tag_id in data:\n",
    "    tags[tag_id] += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-02T05:59:29.846070Z",
     "start_time": "2018-11-02T05:59:29.625277Z"
    }
   },
   "outputs": [],
   "source": [
    "counts = list(tags.values())\n",
    "freqs = set(counts)\n",
    "\n",
    "tag_counts = defaultdict(lambda : 0)\n",
    "\n",
    "for freq in freqs:\n",
    "    tag_counts[freq] = counts.count(freq)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-02T05:59:31.862429Z",
     "start_time": "2018-11-02T05:59:31.467886Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0,0.5,'Log Popularity Time')"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlwAAAGACAYAAAB4CLx5AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3X1clHW+//H3AKOOWCLlTZD9Nt00UzOE0tLTPqQCSw28y9rN0mpd95RWKqVpu2Wm7sFuttpOp21Paacb9UR4W5pR2Wq6hWhmhpWdSkgrlVQYYBiu3x80EwwzzHBzzcDM6/l4+HjINddc38+XOz9+bz5fi2EYhgAAAGCaqFAHAAAAEO5IuAAAAExGwgUAAGAyEi4AAACTkXABAACYjIQLAADAZCRcANq01NRUbd++vcnvT0pK0rffftuCEXlXXl6u6dOnKzk5WTNnzjS9PQCtS0yoAwBgvtTUVC1atEiXXXaZaW08+eSTeuaZZ9SuXTtFR0fr17/+te69914lJSWZ1mZLKCgocP997ty56t69u+6+++4Wb+fNN9/Ujz/+qJ07dyompu6v3j/96U9at26dJMnhcMgwDLVr106SlJycrOeee67F4wEQXIxwAWgxV199tQoKCvTBBx9o8ODBmjFjhlprbeWqqqqgtldcXKxf/epX9ZItSVq4cKEKCgpUUFCgP/zhD+7PY0FBAckWECZIuIAIt2rVKl111VW65JJLNH36dB05csT92j//+U+lp6crOTlZDzzwgG688UatXr3a7zOtVqvGjh2rH374QcePH1d1dbWefvppjRgxQpdeeqnuuecenTx5UpJ06NAh9e3bVytXrtTw4cM1fPhw/eMf/3A/a+7cuXrsscfcH+/cuVOXX36513Y//vhjTZo0SSkpKRo+fLgWLlyoyspK9+t9+/bVSy+9pLS0NKWlpbmvff3111q5cqXWrVunf/zjH0pKStL06dP13HPPacaMGXXaWLRokRYtWuS1/S+//FKTJ09WSkqKRo0apbfffluS9MQTT+jpp5/WG2+8oaSkpIA+h7VVVVVpxowZuuyyy5SSkqLJkyfr4MGD7tePHj2q2267TYMHD9Z1112nZcuWacqUKZIkp9OpBx98UEOHDlVycrKuvfbaOu8FEBwkXEAE++CDD/TII4/o8ccf1z//+U8lJiZq1qxZkqRjx45p5syZmj17tnbu3Klzzz23zvRbQyorK5WTk6OzzjpL8fHxysnJ0euvv64VK1Zoy5YtKisr08KFC+u8Z+fOndq8ebP+8Y9/6O9//3uT1mVFRUVp3rx52rFjh1599VV98MEHevnll+vcs2XLFq1atUobN26sc33SpEkaM2aMbr31VhUUFOiZZ57Rtddeq/fff18nTpyQVJP4bNiwQZmZmfXadjgcmj59uoYNG6bt27drwYIFmjNnjg4ePKiZM2fWGbmaOHFio/t2xRVX6K233tK2bdvUq1cvzZ071/3a/fffr/j4eG3fvl0LFy5Ubm6u+7V33nlHn376qbZs2aIPP/xQjzzyiDp37tzo9gE0DwkXEMHWrVun8ePHq3///mrXrp1mzZql3bt369ChQ9q6davOO+88paWlKSYmRjfddJPOPPPMBp/35ptvKiUlRb/5zW+0b98+PfXUU+52pkyZop49eyo2NlazZs3Sxo0b60zr3X777erYsaP69u2rcePGaf369Y3uz4ABA3TRRRcpJiZGZ599tiZNmqQPP/ywzj3Tpk1TXFycOnTo4Pd53bp1U0pKit58801J0vvvv68uXbpowIAB9e7ds2ePysrKNG3aNLVr106XXnqpRowYoQ0bNjS6H55iYmKUmZmp2NhYtW/fXnfccYc+/vhjVVRUqKKiQnl5ebrzzjvVoUMHnX/++RozZoz7vVarVadOnXKPap133nk644wzmh0TgMZh0TwQwb7//nv179/f/XFsbKzi4uJ05MgRff/99+rRo4f7NYvFUudjb0aOHKlly5Z5bScxMdH9cWJioqqqqnT06FH3tbPOOqvO6wcOHGh0f7766istXbpUn3zyiex2u5xOZ53+ebYTiLFjx+qVV17Rddddp7Vr1yojI8Prfa7PV1TUL/+PTUhIqDNF21RVVVVatmyZ3nrrLR0/flxRUVEyDEMlJSXuRfa1vzY9evTQ/v37JUmXX365Dh48qD/96U86cuSI0tPTlZWVpdjY2GbHBSBwjHABEaxbt24qKipyf1xWVqaSkhJ1795dXbt2rZMsGIahw4cPt0g7xcXFiomJqTPS8t1339V5vVu3bpIkm82m8vJy92s//vijz3YeeOAB9erVS5s2bdKuXbt0991311u0b7FYfL7f22tXXnmlCgsLdeDAAb377rt1Ro88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9Yc//EGHDh3Sq6++qhdeeEEZGRn66KOPlJqaKofDIUk6depUnY8BhD8SLgAhsWjRIo0dO1br1q3TmDFj3FNxDz/8sG666SatW7dOPXr08Pucqqoqbd26VX369NEnn3yinJwcrVq1SitXrtTq1avdZ/t99dVX+u1vf6s33nhDsbGxevnllwOONTk5WatWrVJubq5GjRql5557zv3al19+qRdeeEGPPvqo+9rZZ5+t66+/XlOmTNGaNWuUkpKiIUOG6L333pNUcxRMWlqarFZrwDEAaNtIuACEREFBgUaPHi1JysjIUH5+viRp9+7dGjlypCQ1eDZZeXm5MjIyNH78eCUkJGjChAnKz8/XlVdeqY4dOyo2NlZXXXWVPvroI0nSWWedpeTkZEnStdde624vEIcPH9att96qMWPG6LnnntPnn3/ufi01NVUdOnTw+4wJEybotddek1SzPmzcuHEBtw+g7eMsRQBtkmsNV6AsFovXj6Ojo+U64ayiosLrexctWqQpU6boiiuu0M6dO/XUU0+5X7PZbAG1n5ycrAcffFA7d+6U0+lUnz59Ao4dQNvHCBeAkEhKStKGDRskSevWrVNKSoqkmkNxN2/eLEnu1wOVkpKiLVu2yG63q6ysTFu2bHE/t7i42L2Iff369e7RrsTERH3yySeS5G7X08mTJ9W9e3dJUm5ubkCxxMbGqrS0tM61zMxMzZ49m9EtIAKRcAEwnd1u1+WXX+7+8/zzz+v+++9XTk6OxowZozVr1mj+/PmSpPvuu0/PP/+8xowZo6+//lqdOnUKuJ3+/ftr3Lhxmjhxoq677jpNmDBBF1xwgSTp3HPP1UsvvaSrr75aJ06c0A033CBJuuOOO7R48WKNGzdO0dHRXp97xx136M4779S4ceMUFxcXUCwjRozQW2+95V40L9VMkZ44ccI9lQogclgM11g6ALQCdrtdHTp0kMVi0YYNG7R+/Xr953/+Z7OeeejQIU2fPl3r169voSib5s0339Tbb7+t7OzskMYBIPhYwwWgVdm3b58WLlwowzB0+umna/HixaEOqUU89NBD2rp1q5599tlQhwIgBBjhAgAAMBlruAAAAExGwgUAAGAyEi4AAACTkXABAACYjIQLAADAZCRcAAAAJvv/1mwvXZaCO/UAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 720x432 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sns.set_style(\"whitegrid\")\n",
    "plt.figure(figsize=(10, 6))\n",
    "\n",
    "popularity = np.log1p(list(tag_counts.keys()))\n",
    "popularity_time = np.log1p(list(tag_counts.values()))\n",
    "\n",
    "plt.scatter(popularity, popularity_time)\n",
    "plt.title(\"Log Popularity of Tags\")\n",
    "plt.xlabel(\"Log Popularity\")\n",
    "plt.ylabel(\"Log Popularity Time\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-28T08:30:11.290256Z",
     "start_time": "2018-10-28T08:30:11.279516Z"
    }
   },
   "source": [
    "## 基于标签的基本推荐"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-05T06:50:00.688422Z",
     "start_time": "2018-11-05T06:49:59.116764Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util.delicious_reader import split_data\n",
    "\n",
    "origin_train, origin_test = split_data(\n",
    "                filename=\"data/delicious-2k/user_taggedbookmarks-timestamps.dat\",\n",
    "                k=1,\n",
    "                cv_folder=10\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-05T06:50:07.962313Z",
     "start_time": "2018-11-05T06:50:07.958640Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Len Train : 397695,Len Test : 39898\n"
     ]
    }
   ],
   "source": [
    "print(\"Len Train : {train_count},Len Test : {test_count}\".\n",
    "      format(train_count = len(origin_train), test_count=len(origin_test)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-05T06:50:14.080646Z",
     "start_time": "2018-11-05T06:50:13.597786Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.chapter4.base_rec import BaseRec\n",
    "from main.chapter4 import base_rec\n",
    "from imp import reload\n",
    "reload(base_rec)\n",
    "\n",
    "base_model = BaseRec()\n",
    "base_model.train(origin_data=origin_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 整理测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-05T06:50:17.190266Z",
     "start_time": "2018-11-05T06:50:17.162830Z"
    }
   },
   "outputs": [],
   "source": [
    "test = dict()\n",
    "for user_id, item_id, tag_id in origin_test:\n",
    "    test.setdefault(user_id,[])\n",
    "    test[user_id].append(item_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 计算训练集的流行度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-26T07:20:30.429050Z",
     "start_time": "2018-11-26T07:20:30.253928Z"
    },
    "init_cell": true
   },
   "outputs": [],
   "source": [
    "def popularity(data):\n",
    "    \"\"\"计算数据的流行度\n",
    "    \n",
    "    :param data: tuple(int,int,int)\n",
    "        数据集（user_id, item_id, tag_id）\n",
    "    :return: dict{int, int}\n",
    "        流行度字典{item_id:流行度}\n",
    "    \"\"\"\n",
    "    item_popularity = dict()\n",
    "    for user_id, item_id, tag_id in data:\n",
    "        item_popularity.setdefault(item_id, 0)\n",
    "        item_popularity[item_id] += 1\n",
    "    return item_popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算训练集的流行度\n",
    "train_item_popularity = popularity(origin_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 找出所有商品ID（用于计算覆盖率）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-05T06:50:22.014858Z",
     "start_time": "2018-11-05T06:50:21.900330Z"
    }
   },
   "outputs": [],
   "source": [
    "all_items = set()\n",
    "\n",
    "for user_id, item_id, tag_id in origin_train:\n",
    "    all_items.add(item_id)\n",
    "for user_id, item_id, tag_id in origin_test:\n",
    "    all_items.add(item_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-26T07:20:30.604538Z",
     "start_time": "2018-11-26T07:20:30.431950Z"
    },
    "init_cell": true
   },
   "outputs": [],
   "source": [
    "from main.util import metric\n",
    "\n",
    "def evaluation(test,recommend):\n",
    "    \"\"\"评价\n",
    "    Args:\n",
    "        test: dict {user_id : [买过的商品1，买过的商品2,...]}\n",
    "            测试集\n",
    "        recommend:dict {user_id : [推荐的商品1，推荐的商品2,...]}\n",
    "            测试集推荐结果\n",
    "    Return: tuple\n",
    "        (precision,recall,coverage,popularity)\n",
    "    \"\"\"\n",
    "    precision = metric.precision(recommends=recommend, tests=test)\n",
    "    recall = metric.recall(recommends=recommend, tests=test)\n",
    "    coverage = metric.coverage(all_items=all_items, recommends=recommend)\n",
    "    popularity = metric.popularity(item_popular=train_item_popularity, recommends=recommend)\n",
    "    \n",
    "    return precision,recall,coverage,popularity\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-05T06:55:11.122015Z",
     "start_time": "2018-11-05T06:50:28.846362Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Precision : 0.0004402100430776971\n",
      "Recall : 0.0003961965134706815\n",
      "Coverage : 0.06194472935296072\n",
      "Popularity : 3.7644381689807713\n"
     ]
    }
   ],
   "source": [
    "recommend_count = 20\n",
    "\n",
    "recommend_users = list(test.keys())\n",
    "recommends = base_model.recommend_users(\n",
    "                users=recommend_users,\n",
    "                recommend_count= recommend_count\n",
    ")\n",
    "precision, recall, coverage, popularity = evaluation(test, recommends)\n",
    "\n",
    "print(\"Precision : {}\".format(precision))\n",
    "print(\"Recall : {}\".format(recall))\n",
    "print(\"Coverage : {}\".format(coverage))\n",
    "print(\"Popularity : {}\".format(popularity))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于TFIDF的改进"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:30:04.875478Z",
     "start_time": "2018-11-08T07:30:03.931945Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util.delicious_reader import split_data\n",
    "\n",
    "origin_train, origin_test = split_data(\n",
    "                filename=\"data/delicious-2k/user_taggedbookmarks-timestamps.dat\",\n",
    "                k=1,\n",
    "                cv_folder=10\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T06:55:51.771031Z",
     "start_time": "2018-11-08T06:55:51.767100Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Len Train : 397695,Len Test : 39898\n"
     ]
    }
   ],
   "source": [
    "print(\"Len Train : {train_count},Len Test : {test_count}\".\n",
    "      format(train_count = len(origin_train), test_count=len(origin_test)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:30:12.413312Z",
     "start_time": "2018-11-08T07:30:11.801086Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.chapter4.TFIDF_rec import TagBasedTFIDF\n",
    "from main.chapter4 import TFIDF_rec\n",
    "from imp import reload\n",
    "reload(TFIDF_rec)\n",
    "\n",
    "tfidf_model = TagBasedTFIDF()\n",
    "tfidf_model.train(origin_data=origin_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 整理测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:30:14.331896Z",
     "start_time": "2018-11-08T07:30:14.297050Z"
    }
   },
   "outputs": [],
   "source": [
    "test = dict()\n",
    "for user_id, item_id, tag_id in origin_test:\n",
    "    test.setdefault(user_id,[])\n",
    "    test[user_id].append(item_id)\n",
    "    \n",
    "test = {user_id : set(items) for user_id, items in test.items()}\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 计算训练集的流行度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:30:16.120402Z",
     "start_time": "2018-11-08T07:30:16.115957Z"
    }
   },
   "outputs": [],
   "source": [
    "def popularity(data):\n",
    "    \"\"\"计算数据的流行度\n",
    "    \n",
    "    :param data: tuple(int,int,int)\n",
    "        数据集（user_id, item_id, tag_id）\n",
    "    :return: dict{int, int}\n",
    "        流行度字典{item_id:流行度}\n",
    "    \"\"\"\n",
    "    item_popularity = dict()\n",
    "    for user_id, item_id, tag_id in data:\n",
    "        item_popularity.setdefault(item_id, 0)\n",
    "        item_popularity[item_id] += 1\n",
    "    return item_popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:30:18.657112Z",
     "start_time": "2018-11-08T07:30:18.552096Z"
    }
   },
   "outputs": [],
   "source": [
    "# 计算训练集的流行度\n",
    "train_item_popularity = popularity(origin_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "####  找出所有商品（用于计算覆盖率）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:30:22.663442Z",
     "start_time": "2018-11-08T07:30:22.556161Z"
    }
   },
   "outputs": [],
   "source": [
    "all_items = set()\n",
    "\n",
    "for user_id, item_id, tag_id in origin_train:\n",
    "    all_items.add(item_id)\n",
    "for user_id, item_id, tag_id in origin_test:\n",
    "    all_items.add(item_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:30:25.702113Z",
     "start_time": "2018-11-08T07:30:25.694264Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util import metric\n",
    "\n",
    "def evaluation(test,recommend):\n",
    "    \"\"\"评价\n",
    "    Args:\n",
    "        test: dict {user_id : [买过的商品1，买过的商品2,...]}\n",
    "            测试集\n",
    "        recommend:dict {user_id : [推荐的商品1，推荐的商品2,...]}\n",
    "            测试集推荐结果\n",
    "    Return: tuple\n",
    "        (precision,recall,coverage,popularity)\n",
    "    \"\"\"\n",
    "    precision = metric.precision(recommends=recommend, tests=test)\n",
    "    recall = metric.recall(recommends=recommend, tests=test)\n",
    "    coverage = metric.coverage(all_items=all_items, recommends=recommend)\n",
    "    popularity =   metric.popularity(\n",
    "        item_popular=train_item_popularity,recommends=recommend)\n",
    "    \n",
    "    return precision,recall,coverage,popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:34:35.136382Z",
     "start_time": "2018-11-08T07:30:46.538078Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Precision : 0.0004402100430776971\n",
      "Recall : 0.0003961965134706815\n",
      "Coverage : 0.08370050416768993\n",
      "Popularity : 3.671448547935441\n"
     ]
    }
   ],
   "source": [
    "recommend_count = 20\n",
    "\n",
    "recommend_users = list(test.keys())\n",
    "recommends = tfidf_model.recommend_users(\n",
    "                users=recommend_users,\n",
    "                recommend_count= recommend_count\n",
    ")\n",
    "precision, recall, coverage, popularity = evaluation(test, recommends)\n",
    "\n",
    "print(\"Precision : {}\".format(precision))\n",
    "print(\"Recall : {}\".format(recall))\n",
    "print(\"Coverage : {}\".format(coverage))\n",
    "print(\"Popularity : {}\".format(popularity))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TFIDF++"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:43:50.728846Z",
     "start_time": "2018-11-08T07:43:49.764986Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util.delicious_reader import split_data\n",
    "\n",
    "origin_train, origin_test = split_data(\n",
    "                filename=\"data/delicious-2k/user_taggedbookmarks-timestamps.dat\",\n",
    "                k=1,\n",
    "                cv_folder=10\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:44:03.771757Z",
     "start_time": "2018-11-08T07:44:03.765776Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Len Train : 397695,Len Test : 39898\n"
     ]
    }
   ],
   "source": [
    "print(\"Len Train : {train_count},Len Test : {test_count}\".\n",
    "      format(train_count = len(origin_train), test_count=len(origin_test)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:46:42.586302Z",
     "start_time": "2018-11-08T07:46:41.544689Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.chapter4.TFIDF_plus_rec import TagBasedTFIDFPlus\n",
    "from main.chapter4 import TFIDF_plus_rec\n",
    "from imp import reload\n",
    "reload(TFIDF_plus_rec)\n",
    "\n",
    "tfidf_plus_model = TagBasedTFIDFPlus()\n",
    "tfidf_plus_model.train(origin_data=origin_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 整理测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:47:30.485434Z",
     "start_time": "2018-11-08T07:47:30.445339Z"
    }
   },
   "outputs": [],
   "source": [
    "test = dict()\n",
    "for user_id, item_id, tag_id in origin_test:\n",
    "    test.setdefault(user_id,[])\n",
    "    test[user_id].append(item_id)\n",
    "    \n",
    "test = {user_id : set(items) for user_id, items in test.items()}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 计算训练集的流行度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:48:02.204311Z",
     "start_time": "2018-11-08T07:48:02.200038Z"
    }
   },
   "outputs": [],
   "source": [
    "def popularity(data):\n",
    "    \"\"\"计算数据的流行度\n",
    "    \n",
    "    :param data: tuple(int,int,int)\n",
    "        数据集（user_id, item_id, tag_id）\n",
    "    :return: dict{int, int}\n",
    "        流行度字典{item_id:流行度}\n",
    "    \"\"\"\n",
    "    item_popularity = dict()\n",
    "    for user_id, item_id, tag_id in data:\n",
    "        item_popularity.setdefault(item_id, 0)\n",
    "        item_popularity[item_id] += 1\n",
    "    return item_popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:48:13.320044Z",
     "start_time": "2018-11-08T07:48:13.213616Z"
    }
   },
   "outputs": [],
   "source": [
    "# 计算训练集的流行度\n",
    "train_item_popularity = popularity(origin_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 找出所有商品（用于计算覆盖率）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:48:38.991209Z",
     "start_time": "2018-11-08T07:48:38.895535Z"
    }
   },
   "outputs": [],
   "source": [
    "all_items = set()\n",
    "\n",
    "for user_id, item_id, tag_id in origin_train:\n",
    "    all_items.add(item_id)\n",
    "for user_id, item_id, tag_id in origin_test:\n",
    "    all_items.add(item_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:48:54.143307Z",
     "start_time": "2018-11-08T07:48:54.139218Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util import metric\n",
    "\n",
    "def evaluation(test,recommend):\n",
    "    \"\"\"评价\n",
    "    Args:\n",
    "        test: dict {user_id : [买过的商品1，买过的商品2,...]}\n",
    "            测试集\n",
    "        recommend:dict {user_id : [推荐的商品1，推荐的商品2,...]}\n",
    "            测试集推荐结果\n",
    "    Return: tuple\n",
    "        (precision,recall,coverage,popularity)\n",
    "    \"\"\"\n",
    "    precision = metric.precision(recommends=recommend, tests=test)\n",
    "    recall = metric.recall(recommends=recommend, tests=test)\n",
    "    coverage = metric.coverage(all_items=all_items, recommends=recommend)\n",
    "    popularity =   metric.popularity(\n",
    "        item_popular=train_item_popularity,recommends=recommend)\n",
    "    \n",
    "    return precision,recall,coverage,popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-08T07:53:43.029587Z",
     "start_time": "2018-11-08T07:49:43.793323Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Precision : 0.0004087664685721473\n",
      "Recall : 0.00036789676250848993\n",
      "Coverage : 0.1766609363939731\n",
      "Popularity : 2.766799687261488\n"
     ]
    }
   ],
   "source": [
    "recommend_count = 20\n",
    "\n",
    "recommend_users = list(test.keys())\n",
    "recommends = tfidf_plus_model.recommend_users(\n",
    "                users=recommend_users,\n",
    "                recommend_count= recommend_count\n",
    ")\n",
    "precision, recall, coverage, popularity = evaluation(test, recommends)\n",
    "\n",
    "print(\"Precision : {}\".format(precision))\n",
    "print(\"Recall : {}\".format(recall))\n",
    "print(\"Coverage : {}\".format(coverage))\n",
    "print(\"Popularity : {}\".format(popularity))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 标签的相关性报告"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T08:12:33.552872Z",
     "start_time": "2018-11-12T08:12:32.539844Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util.delicious_reader import split_data\n",
    "\n",
    "origin_train, origin_test = split_data(\n",
    "                filename=\"data/delicious-2k/user_taggedbookmarks-timestamps.dat\",\n",
    "                k=1,\n",
    "                cv_folder=10\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T07:05:57.471410Z",
     "start_time": "2018-11-12T07:05:56.291887Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.chapter4 import sim_tag_rec\n",
    "from imp import reload\n",
    "reload(sim_tag_rec)\n",
    "\n",
    "model = sim_tag_rec.SimTagTFIDF()\n",
    "model.train(origin_data=origin_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T07:05:59.120863Z",
     "start_time": "2018-11-12T07:05:58.570045Z"
    }
   },
   "outputs": [],
   "source": [
    "similarity_matrix = model.tag_vec_report(tops=30)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T07:06:09.976630Z",
     "start_time": "2018-11-12T07:06:09.250945Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x7f6f0dbc5978>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 720x576 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import seaborn as sns\n",
    "sns.set_style(\"whitegrid\")\n",
    "plt.figure(figsize=(10,8))\n",
    "\n",
    "plt.title(\"Tag Similarity Heat Maps\")\n",
    "plt.xlabel(\"Tags\")\n",
    "plt.ylabel(\"Tags\")\n",
    "sns.heatmap(similarity_matrix,cmap=plt.cm.Blues,)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 考虑加入标签协同过滤方式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T08:18:12.412627Z",
     "start_time": "2018-11-12T08:18:11.223574Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.chapter4 import sim_tag_rec\n",
    "from imp import reload\n",
    "reload(sim_tag_rec)\n",
    "\n",
    "model = sim_tag_rec.SimTagTFIDF()\n",
    "model.train(origin_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 整理测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T08:18:13.812145Z",
     "start_time": "2018-11-12T08:18:13.772289Z"
    }
   },
   "outputs": [],
   "source": [
    "test = dict()\n",
    "for user_id, item_id, tag_id in origin_test:\n",
    "    test.setdefault(user_id,[])\n",
    "    test[user_id].append(item_id)\n",
    "    \n",
    "test = {user_id : set(items) for user_id, items in test.items()}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 计算测试集流行度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T08:18:15.609453Z",
     "start_time": "2018-11-12T08:18:15.604614Z"
    }
   },
   "outputs": [],
   "source": [
    "def popularity(data):\n",
    "    \"\"\"计算数据的流行度\n",
    "    \n",
    "    :param data: tuple(int,int,int)\n",
    "        数据集（user_id, item_id, tag_id）\n",
    "    :return: dict{int, int}\n",
    "        流行度字典{item_id:流行度}\n",
    "    \"\"\"\n",
    "    item_popularity = dict()\n",
    "    for user_id, item_id, tag_id in data:\n",
    "        item_popularity.setdefault(item_id, 0)\n",
    "        item_popularity[item_id] += 1\n",
    "    return item_popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T08:18:17.853126Z",
     "start_time": "2018-11-12T08:18:17.749028Z"
    }
   },
   "outputs": [],
   "source": [
    "# 计算训练集的流行度\n",
    "train_item_popularity = popularity(origin_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 找出所有商品（用于计算覆盖率）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T08:18:20.971160Z",
     "start_time": "2018-11-12T08:18:20.856377Z"
    }
   },
   "outputs": [],
   "source": [
    "all_items = set()\n",
    "\n",
    "for user_id, item_id, tag_id in origin_train:\n",
    "    all_items.add(item_id)\n",
    "for user_id, item_id, tag_id in origin_test:\n",
    "    all_items.add(item_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T08:18:21.952990Z",
     "start_time": "2018-11-12T08:18:21.948156Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util import metric\n",
    "\n",
    "def evaluation(test,recommend):\n",
    "    \"\"\"评价\n",
    "    Args:\n",
    "        test: dict {user_id : [买过的商品1，买过的商品2,...]}\n",
    "            测试集\n",
    "        recommend:dict {user_id : [推荐的商品1，推荐的商品2,...]}\n",
    "            测试集推荐结果\n",
    "    Return: tuple\n",
    "        (precision,recall,coverage,popularity)\n",
    "    \"\"\"\n",
    "    precision = metric.precision(recommends=recommend, tests=test)\n",
    "    recall = metric.recall(recommends=recommend, tests=test)\n",
    "    coverage = metric.coverage(all_items=all_items, recommends=recommend)\n",
    "    popularity =   metric.popularity(\n",
    "        item_popular=train_item_popularity,recommends=recommend)\n",
    "    \n",
    "    return precision,recall,coverage,popularity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-12T09:34:58.417814Z",
     "start_time": "2018-11-12T08:18:25.406333Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Precision : 0.0004087664685721473\n",
      "Recall : 0.0003665999266800147\n",
      "Coverage : 0.17732545541221847\n",
      "Popularity : 2.7667086359589597\n"
     ]
    }
   ],
   "source": [
    "recommend_count = 20\n",
    "\n",
    "recommend_users = list(test.keys())\n",
    "recommends = model.recommend_users(\n",
    "                users=recommend_users,\n",
    "                recommend_count= recommend_count\n",
    ")\n",
    "precision, recall, coverage, popularity = evaluation(test, recommends)\n",
    "\n",
    "print(\"Precision : {}\".format(precision))\n",
    "print(\"Recall : {}\".format(recall))\n",
    "print(\"Coverage : {}\".format(coverage))\n",
    "print(\"Popularity : {}\".format(popularity))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Chapter5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 时间特性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-23T06:59:46.212980Z",
     "start_time": "2018-11-23T06:59:44.555910Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>UserID</th>\n",
       "      <th>ItemID</th>\n",
       "      <th>TagID</th>\n",
       "      <th>Time</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>8</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>2010-11-09 06:29:22</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>8</td>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>2010-11-09 06:25:59</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>8</td>\n",
       "      <td>7</td>\n",
       "      <td>1</td>\n",
       "      <td>2010-11-09 01:55:01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>8</td>\n",
       "      <td>7</td>\n",
       "      <td>6</td>\n",
       "      <td>2010-11-09 01:55:01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>8</td>\n",
       "      <td>7</td>\n",
       "      <td>7</td>\n",
       "      <td>2010-11-09 01:55:01</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   UserID  ItemID  TagID                Time\n",
       "0       8       1      1 2010-11-09 06:29:22\n",
       "1       8       2      1 2010-11-09 06:25:59\n",
       "2       8       7      1 2010-11-09 01:55:01\n",
       "3       8       7      6 2010-11-09 01:55:01\n",
       "4       8       7      7 2010-11-09 01:55:01"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from main.util import delicious_reader\n",
    "from imp import reload\n",
    "reload(delicious_reader)\n",
    "\n",
    "path = \"data/delicious-2k/user_taggedbookmarks-timestamps.dat\"\n",
    "\n",
    "tag_time = delicious_reader.read_tag_time(path)\n",
    "tag_time_df = pd.DataFrame(tag_time,columns=[\"UserID\",\"ItemID\",\"TagID\",\"Time\"])\n",
    "tag_time_df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 找到打标签最多的商品"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-23T07:06:59.745463Z",
     "start_time": "2018-11-23T07:06:59.727937Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5448     158\n",
       "8981     154\n",
       "11115    147\n",
       "2720     142\n",
       "1752     142\n",
       "Name: ItemID, dtype: int64"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tag_time_df.ItemID.value_counts().head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 热度统计"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-23T07:45:21.038185Z",
     "start_time": "2018-11-23T07:45:20.850597Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:2: SettingWithCopyWarning: \n",
      "A value is trying to be set on a copy of a slice from a DataFrame.\n",
      "Try using .loc[row_indexer,col_indexer] = value instead\n",
      "\n",
      "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n",
      "  \n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>UserID</th>\n",
       "      <th>ItemID</th>\n",
       "      <th>TagID</th>\n",
       "      <th>Time</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2010-06-25</th>\n",
       "      <td>4</td>\n",
       "      <td>4</td>\n",
       "      <td>4</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-08-11</th>\n",
       "      <td>40</td>\n",
       "      <td>40</td>\n",
       "      <td>40</td>\n",
       "      <td>40</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-08-12</th>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-08-13</th>\n",
       "      <td>9</td>\n",
       "      <td>9</td>\n",
       "      <td>9</td>\n",
       "      <td>9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-08-16</th>\n",
       "      <td>6</td>\n",
       "      <td>6</td>\n",
       "      <td>6</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            UserID  ItemID  TagID  Time\n",
       "Date                                   \n",
       "2010-06-25       4       4      4     4\n",
       "2010-08-11      40      40     40    40\n",
       "2010-08-12      15      15     15    15\n",
       "2010-08-13       9       9      9     9\n",
       "2010-08-16       6       6      6     6"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Item_5448 = tag_time_df.loc[tag_time_df.ItemID == 5448]\n",
    "Item_5448[\"Date\"] = Item_5448.Time.apply(lambda x: x.date())\n",
    "Item_5448 = Item_5448.groupby(\"Date\",sort=True).count()\n",
    "Item_5448.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 画图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-23T07:59:08.973651Z",
     "start_time": "2018-11-23T07:59:08.614623Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x7feb06d89198>"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAmgAAAGpCAYAAAA5s8rFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvDW2N/gAAIABJREFUeJzs3Xd4lGX2N/DvlEx674UEQwsl0ntABaWINAEbFpBVURRdVl2U3XddVsCfFcXCYkFUsCFJUFQUWBEFpEOE0CEhIcmkTXoy7Xn/mMIMJJm0Z+r3c11eVzLPzDOHgMPh3Pd9jkQQBAFERERE5DSkjg6AiIiIiKwxQSMiIiJyMkzQiIiIiJwMEzQiIiIiJ8MEjYiIiMjJMEEjIiIicjJM0IiImrB69WosWbKkza+fNGkS/vjjjw6MyPFycnLQo0cPR4dB5PaYoBG5uDFjxmD37t1YvXo1+vfvj/79+yM1NRU9e/Y0fz9p0iQAQI8ePdCvXz/z4/3798f7778PAFi1ahV69OiBdevWWd1/3bp16NGjB1atWtXo+//xxx9ISUmxumd6evo1z7t48SJSU1Px9NNPN3qf5557Dj169EBOTo75sby8PDz00EMYPHgwRo4ciaVLl0Kr1V7z2qKiIvTq1Qu5ubnXXFuwYAH+7//+r4mfXvPmz5+PZcuWtei5ixcvxhtvvGH12JYtWzB06NA2vXdTJk2aZP459+zZE6mpqebvV69e3aHvRUSOI3d0AETUMebPn4/58+cDADZt2oSvv/4an3/++TXPy8zMRFJSUqP36Ny5MzIzM/HAAw+YH8vIyEDnzp2bfe+oqCj8+uuvzT5n6dKlSE1NbfTagQMHcOnSpWse//e//43w8HD89ttvqKysxIMPPogNGzbg/vvvt3pedHQ0hg8fjszMTDzxxBPmx1UqFXbu3Ilvvvmm2dgao9VqIZc730fkli1bzF/fd999mDJlCmbNmtXk853110FEzWMFjYjMUlNTUVdXhzNnzgAAzpw5g4aGhiYTq5basmULAgMDMXz48GuuabVavPjii/jHP/5xzbW8vDxMnDgR3t7eiIyMRFpaGs6ePdvoe0ybNg2ZmZnXvG/Xrl3NS3IvvvgibrjhBgwYMAC33347Dhw4YH7uqlWrsHDhQjz99NMYMGAA0tPTsWrVKquK38KFCzFy5EgMHDgQs2fPNv+cvvzyS3z77bf48MMP0b9/f3OibKpuAoBarcayZcuQlpaGtLQ0LFu2DGq1GoChCjl69Gh89NFHGD58ONLS0tqUVALA119/jdmzZ+PFF1/EkCFD8N5775kfnzBhAgYPHoy//OUvKCgoAGD4+ffo0QNffPEFbrnlFgwePBgvvvii+X46nQ7Lly/H0KFDMXbsWOzatatNcRFR6zBBIyIrU6dORUZGBgAgPT0dU6dOtfmasrIyjBgxAmPGjMHy5ctRW1trvlZdXY233noLzz33XKOv/fjjjzFo0CCkpKRcc+2BBx7Ali1bUFdXh6KiIuzatQujRo1q9D633HILysvLrZKuzZs3Y9q0aebvU1NTkZGRgX379uG2227Dk08+iYaGBvP17du3Y8KECThw4AAmT558zXuMHj0aW7duxZ49e9CrVy9z8nbnnXdi8uTJmDdvHg4fPtzoUuN7772Ho0ePIjMzE5s3b0ZWVhbeffdd8/WSkhJUVVXh119/xbJly7B06VJUVFQ0+mu15fDhw0hOTsaePXvw0EMPYevWrfjggw/w7rvvYs+ePejbty/+9re/Wb1m586d2LRpE9LT07F582ZzYvn555/j999/R2ZmJjZu3IgffvihTTERUeswQSPyMNOnT8egQYPM/11dEZkyZQq2bNkCjUaD77//HlOmTGn2fsnJycjIyMBvv/2GdevW4fjx43jppZfM11euXIkZM2YgJibmmtcWFBTgyy+/xJNPPtnovQcPHoyzZ89i4MCBGD16NPr06YObb7650ef6+PhgwoQJ5iraxYsXcfz4catEa+rUqQgNDYVcLseDDz4ItVqNCxcumK/369cPN998M6RSKXx8fK55j5kzZyIgIAAKhQJPPPEETp48iaqqqmZ/PibffvstFixYgPDwcISFhWHBggXYvHmz+bpcLseCBQvg5eWFG264AX5+flaxtUZsbCzuueceyGQy+Pj44IsvvsD8+fORnJwMuVyORx99FMeOHUNRUZH5NY888ggCAwORkJCAIUOGIDs7GwDwww8/YM6cOYiJiUFoaCgefvjhNsVERK3DBI3Iw6Snp+PAgQPm/66uSMXFxSExMRGvv/46kpKSEBsb2+z9IiMj0bVrV0ilUnTq1AnPPPMMtm7dCgDIzs7Gnj17MGfOnEZfu3z5cixYsACBgYHX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\n",
      "text/plain": [
       "<Figure size 720x432 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,6))\n",
    "sns.set_style(\"darkgrid\")\n",
    "\n",
    "plt.xticks(rotation=45)\n",
    "plt.title(\"ITEM 5448 Variation Trend\")\n",
    "\n",
    "Item_5448[\"Tag Count\"] = Item_5448[\"ItemID\"]\n",
    "sns.pointplot(x=Item_5448.index,y=\"Tag Count\",data=Item_5448)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 最近最热门"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-26T07:22:26.086480Z",
     "start_time": "2018-11-26T07:22:24.420299Z"
    }
   },
   "outputs": [],
   "source": [
    "from main.util import delicious_reader\n",
    "\n",
    "data = delicious_reader.read_tag_time(\"data/delicious-2k/user_taggedbookmarks-timestamps.dat\")\n",
    "data = [[user_id,item_id,ui_time] for user_id, item_id, tag_id, ui_time in data]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-26T07:25:24.625997Z",
     "start_time": "2018-11-26T07:25:24.618320Z"
    }
   },
   "outputs": [],
   "source": [
    "from imp import reload\n",
    "from main.chapter5 import most_popularity\n",
    "reload(most_popularity)\n",
    "\n",
    "model = most_popularity.RecentPopular()\n",
    "model.train(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 推荐"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-11-26T07:27:00.211573Z",
     "start_time": "2018-11-26T07:27:00.010612Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "推荐的最近热门商品ID:[5448, 8981, 11115, 1752, 2720, 1087, 7535, 1303, 4114, 4041]\n"
     ]
    }
   ],
   "source": [
    "print(\"推荐的最近热门商品ID:{0}\".format(model.recommend(alpha=0.1)))"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Initialization Cell",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": true,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "370px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
